// 生成且配置 axios 实例
import axios from "axios";
//引入 storage 获取token
import * as storage from "@/utils/storage";

// 引入elementUI的提示框
import ElementUI from "element-ui";

// 引入路由 用来当请求返回的状态是401/403时 进行编程式路由的跳转 跳转到登录页面
import router from "@/router";
// 引入cache.js 的 方法
import {
  addCancelConfig,
  getApiCache,
  hasApiCache,
  setApiCache,
} from "./cache";
// 声明 Message
const Message = ElementUI.Message;

const instance = axios.create({
  baseURL: "http://www.zhaochong.top:7000",
  timeout: 5000, // 请求超时时间 超过5s 请求超过5s这个请求就失效
});

// axios 请求 和 响应  拦截器
// 在 请求或响应由 或 处理之前对其进行拦截。then catch
//
// 添加请求拦截器  一般在请求拦截器中 设置通用的请求头部 两个函数  一个处理请求成功的函数，一个处理请求失败的函数
instance.interceptors.request.use(
  (config) => {
    // console.log("config", config);
    //为每一个请求在请求头中加上token
    const token = storage.get("z-admin-token");
    //如果 有token 就加上token
    if (token) {
      config.headers["Authorization"] = `jwt ${token}`;
    }
    const { url, params } = config;
    // 判断是否 请求中是否包含此请求地址的缓存
    // console.log(hasApiCache(url,params))

    const cancel = addCancelConfig(url, config);
    if (hasApiCache(url, params)) {
      //  cancel 的两个作用：
      //  1.取消此次请求
      //  2.把getApiCache(url,params)的结果传给响应对象，响应对象(拦截器)要在错误的函数中获取传过来的结果
      // noinspection JSValidateTypes
      cancel(getApiCache(url, params));
    }

    // 一定要返回 config
    return config;
  },
  (err) => Promise.reject(err)
);

//响应拦截器 从axios里面  做了请求 获取相应数据 之前 会经过这个响应拦截器
instance.interceptors.response.use(
  (response) => {
    // console.log("response", response);
    const {
      status,
      data,
      config: { url, params },
    } = response;

    // 1. 第一次请求的结果，在响应拦截器中保存下来
    // 设置缓存(商品列表)
    setApiCache(url, data, params);

    if (status === 201) {
      Message.success("创建成功");
    } else if (status === 204) {
      Message.success("删除成功");
    }

    // Message.success('响应成功')
    // Notification.success("响应成功 ");
    return data;
  },
  (err) => {
    console.log("err", err);
    const { response } = err;
    // 定义一个故障信息对象 发生错误直接返回info
    const info = { status: "", responseText: "" };
    //网络故障  没有response对象
    if (!response) {
      // console.log("网络故障");
      info.status = 5000;
      info.responseText = "网络故障";
      // this.$message.error(info.responseText)  // 需要引入 Vue 实例 才呢能使用$message
      Message.error(info.responseText);
      return Promise.reject(info);
    }
    // 如果response存在 就根据response中status的状态码 返回 info
    const { status, responseText } = response;
    // 4字头
    if (status === 401) {
      //认证失败两种情况：1.用户名或密码错误，返回401认证失败 2.当前你没有认证，是否返回一个需要认证的页面
      info.responseText = "认证失败！请确认用户名或密码，重新登陆！";
    } else if (status === 403) {
      info.responseText = "没有足够的权限";
    } else if (status === 404) {
      info.responseText = "请求的资源不存在";
    } else if (status === 400) {
      // 400:bag request
      info.responseText = "请求参数不合法 或者 上传文件过大！";
    } else if (status.toString().startsWith("5")) {
      // 5字头  服务端问题
      info.responseText = "服务端异常！";
    } else {
      info.responseText = responseText;
    }
    // 权限不够 返回Login页面
    if (status === 401 || status === 403) {
      // 从 router中获取下 当下的路由地址，如果不是/login 就跳转到/login 进行登录
      const {
        history: {
          current: { path },
        },
      } = router; // 对象的解构  router.history.current.path
      // console.log("path", path);
      if (path !== "/login") {
        // 编程式路由跳转
        router.push({ name: "Login", params: { callback: path } });
      }
    }

    info.status = status;
    // console.log("----");
    Message.error(info.responseText);

    // console.dir(err)
    return Promise.reject(info);
  }
);

export default instance;
